package czk.concrent.juc.AQS;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * @Author:ChenZhangKun
 * @Date: 2021/9/16 11:54
 */
public class ReEnterLock {
    public static void main(String[] args) {
        // 加锁三次
        ReEnterLock reEnterLock = new ReEnterLock();
        for (int i = 0; i < 3; i++) {
            if (reEnterLock.lock()) {
                System.out.println("加锁成功" + i);
            }
        }
        // 释放锁
        for (int i = 0; i < 3; i++) {
            if (reEnterLock.unLock()) {
                // 最后一次才释放成功
                System.out.println("释放锁成功" + i);
            }
        }
        System.out.println("==================");
        // 创建线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 3; i++) {
            int j = i;
            threadPool.execute(() -> {
                // 此时只有一个线程会加锁成功
                if (reEnterLock.lock()) {
                    System.out.println("加锁成功了" + j);
                }
            });
        }
    }

    private static class MyLock extends AbstractQueuedSynchronizer {
        /**
         * 可重入锁的获取
         *
         * @param arg
         * @return
         */
        @Override
        protected boolean tryAcquire(int arg) {
            // 拿到state
            int state = getState();
            // 拿到当前线程
            Thread thread = Thread.currentThread();
            // 是否为1
            if (state == 0) {
                // 设置为1
                if (compareAndSetState(0, arg)) {
                    // 获取锁成功
                    setExclusiveOwnerThread(thread);
                    return true;
                }
            } else {
                if (thread == getExclusiveOwnerThread()) {
                    // 线程相同，表示重入锁
                    setState(++state);
                    return true;
                }
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            // 是否是当前锁
            if (getExclusiveOwnerThread() != Thread.currentThread()) {
                throw new RuntimeException("操作非法");
            }
            int i = getState() - arg;
            setState(i);
            if (getState() == 0) {
                // 解锁成功
                setExclusiveOwnerThread(null);
                return true;
            }
            // 解锁所失败
            return false;
        }
    }

    private MyLock myLock = new MyLock();

    public boolean lock() {
        return myLock.tryAcquire(1);
    }

    public boolean unLock() {
        return myLock.tryRelease(1);
    }
}
